#include <iostream>

#include <nemesis.CommandLine.h>
#include <nemesis.DataBlock.h>
#include <nemesis.TraceWriter.h>
#include <nemesis.Logger.h>

#include <nemesis.comm.h>

#include <nemesis.app.Application.h>

class MyCodec : public Codec {
public:
   MyCodec () : Codec (0xaa, false) 
   {
      attach ("string", 10, a_string);
      attach ("integer", 20, a_integer);
   }

   void set (const char* value) throw () { a_string = value; }
   void set (const int value) throw () { a_integer = value; }

   const std::string& getString () const throw () { return a_string; }
   const int getInteger () const throw () { return a_integer; }

private:
   std::string a_string;
   int a_integer;
};

class Test : public nemesis::app::Application {
public:
   Test ();

private:
   MyCodec a_input;
   MyCodec a_output;

   void run () throw (nemesis::RuntimeException);
};

using namespace std;
using namespace nemesis;

int main (int argc, const char** argv)
{
   CommandLine& commandLine (CommandLine::instanciate ());
   Test test;
   TraceWriter traceWriter ("my.trace", 2048000);

   try {
      commandLine.initialize (argv, argc);
      commandLine.verify ();

      Logger::initialize ("testfunctions", &traceWriter);
      Logger::setLevel (Logger::Debug);

      test.start ();
   }
   catch (Exception& ex) {
      cout << ex.asString () << endl;
   }

   return 0;
}

Test::Test () :
   nemesis::app::Application ("testfunctions", "Comprobacin de la clase Codec", "1.0")
{
   CommandLine& commandLine (CommandLine::instanciate ());

   commandLine.add ("i", CommandLine::Argument::Mandatory, "Enterno a enviar");
}

void Test::run ()
   throw (RuntimeException)
{
   CommandLine& cm (CommandLine::instanciate ());
   LargeBinaryCodec input (1, false);
   LargeBinaryCodec output (1, false);

   a_input.set ("12345");
   a_input.set (cm.getIntegerValue ("i"));

   input += a_input.code ();

   a_input.set ("6789");
   a_input.set (cm.getIntegerValue ("i") + 10);
   input += a_input.code ();

   a_input.set ("abcdefg");
   a_input.set (cm.getIntegerValue ("i") + 20);
   input += a_input.code ();

   const DataBlock& all = input.code ();  // Codifica el LBC.

   output.decode (all);                   // Lo decodific

   for (LargeBinaryCodec::const_iterator ii = output.begin (), maxii = output.end (); ii != maxii; ii ++) {
      const DataBlock& chunk = *LargeBinaryCodec::data (ii);

      Logger::debug (nemesis::functions::asString (chunk), FILE_LOCATION);

      a_output.decode (chunk);

      cout << "String: " << a_output.getString () << endl;
      cout << "Integer: " << a_output.getInteger () << endl << endl;
   }
}

